Android EventBus3.0源码分析

在我们开发过程中,相信应该有很多人使用过EventBus 3.0,这个确实方便了我们,少些了很多代码,这是个优秀的库,我们接下来进行对他剖析。
我们使用EventBus 3.0的过程:

1
2
3
EventBus.getDefault().register()
EventBus.getDefault().post()
EventBus.getDefault().unregister()

我们先看看是怎么初始化的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}

/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}

EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}

一个单例模式,接着点你会发现其实是利用的Builder模式,而框架内部帮我们写了一个EventBusBuilder

1
2
3
4
5
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

EventBusBuilder() {

}

EventBusBuilder初始化的时候除了对成员变量的一些初始化外,其他的并没有做什么操作。
接下来我们进入register函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//根据subscriberClass 获取订阅的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
//遍历订阅
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}

从这个函数我们可以很清晰的看到逻辑,首先根据subscriber(Activity,Fragment)得到相应的订阅方法,然后在遍历订阅。这里代码就不点进去看了,主要说下框架的实现思路。

采用了缓存加反射的方式,主要的参数和类为下:
METHOD_CACHE:一个key为订阅者classvalue为需要订阅实现的方法的一个ConcurrentHashMap,这个HashMap是为了保证线程并发安全。我们获取的订阅方法就会缓存到这里面。
FindState:顾名思义,这是一个检测状态的类,里面的参数为

1
2
3
4
5
6
7
8
9
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);

Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;

里面比较重要的几个参数:
SubscriberMethod: 当前订阅对象(Activity,Fragment)的订阅方法实体。

1
2
3
4
5
6
7
8
9
10
11
public class SubscriberMethod {
//方法
final Method method;
//模式
final ThreadMode threadMode;
//类型, 就是参数的类型 参数只能为1个
final Class<?> eventType;
final int priority;
final boolean sticky;
/** Used for efficient comparison */
String methodString;

subscriberMethods:用来存储当前订阅对象(Activity,Fragment)内的订阅方法SubscriberMethod
anyMethodByEventType: key为参数类型(订阅类型),value为方法的一个缓存。
subscriberClassByMethodKey:key订阅方法名+">"+参数类型name,value为订阅方法的class

获取订阅方法的时候先判断缓存里面是否存在,不存在就获取FindState实例,根据反射获取注解Subscribe(Activity,Fragment)的方法,然后对FindState实例进行操作(anyMethodByEventTypesubscriberClassByMethodKey得到相应的值或添加到缓存),获取到的订阅方法集合其实就是FindState实例里面的subscriberMethods,最后在把获取的订阅方法集合加入缓存。
得到了订阅方法集合接下来就遍历subscriberMethods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;


// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}

int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}

List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);

if (subscriberMethod.sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}

订阅的时候,首先根据订阅者(Activity Fragment)SubscriberMethod得到一个Subscription对象,这个类就是一个真正执行信息传递的订阅对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
* Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.greenrobot.eventbus;

final class Subscription {
final Object subscriber;
final SubscriberMethod subscriberMethod;
/**
* Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
* {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
*/
volatile boolean active;

Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
active = true;
}

@Override
public boolean equals(Object other) {
if (other instanceof Subscription) {
Subscription otherSubscription = (Subscription) other;
return subscriber == otherSubscription.subscriber
&& subscriberMethod.equals(otherSubscription.subscriberMethod);
} else {
return false;
}
}

@Override
public int hashCode() {
return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
}
}

接着把这个Subscription对象添加CopyOnWriteArrayListCopyOnWriteArrayList是一个适合用在读多,写少并发应用中,它是一个线程安全的集合)然后将这个CopyOnWriteArrayList添加到subscriptionsByEventType里面,这个subscriptionsByEventType是一个key为订阅方法的类型(方法函数的类型),value为一个存放SubscriptionCopyOnWriteArrayListHashMap。接下来把订阅方法的类型(参数类型)eventType添加到一个ArrayList里面,在将这个ArrayList添加到typesBySubscribertypesBySubscriber是一个key为订阅者对象(Fragment,Activity),valueArrayList<Class<?>>HashMap,最后在判断是否是sticky,如果是的就将遍历一个stickyEventsHashMap,然后根据key(订阅方法类型)发出消息。

我们看看unregister

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}

/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}

很简单,先根据订阅者(Activity Fragment)获取到typesBySubscriber里面的订阅方法类型集合(List<Class<?>> subscribedTypes),然后遍历这个集合,根据这个订阅方法类型得到subscriptionsByEventType里面的订阅对象集合List<Subscription> subscriptions,在遍历这个subscriptions集合,判断subscription.subscriber == subscriber然后移除,最后在移除typesBySubscriber里面的这个订阅对象(Fragment ,Activity )

接下来我们看看post,最终会走到这个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}


/**
* Invokes the subscriber if the subscriptions is still active. Skipping subscriptions prevents race conditions
* between {@link #unregister(Object)} and event delivery. Otherwise the event might be delivered after the
* subscriber unregistered. This is particularly important for main thread delivery and registrations bound to the
* live cycle of an Activity or Fragment.
*/
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}

void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}

在发送消息的时候根据消息类型(参数类型)然后从上面的subscriptionsByEventType里面取出相应的数据进行封装成一个PendingPost对象,在根据反射invoke对应的方法即可,如果是MAIN的话就通过Handler进行线程转换,如果是BACKGROUND并且是在主线程中调用或者是ASYNC将会通过线程池来进行线程切换。

接下来看看postSticky

1
2
3
4
5
6
7
8
9
10
11
/**
* Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
* event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}.
*/
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}

这个其实我们在注册的时候已经分析了,当调用这个函数的时候,将会将这个消息加到stickyEvents里面,这个stickyEvents是一个ConcurrentHashMap,ConcurrentHashMap是一个应用于高并发的键值对,接着调用post函数先把已经注册的观察者的方法实现,接下来其他对象注册的时候

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (subscriberMethod.sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}

在这里将会调用。
还有一个优先级priority问题,可以看到也是在注册的时候

1
2
3
4
5
6
7
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}

其实也是很简单的原理。源码分析得也差不多了,具体的需要大家自己去查看源码。


总结,EventBus的实现方式:反射 + 数据封装 + 缓存 + 线程切换
通过查看EventBus的源码收获了什么?

1. Builder模式封装参数
2. 根据用处不同进行对不同的类封装,比如:`SubscriberMethodFinder`用于订阅方法的查找;`FindState`一个用`SubscriberMethodFinder`查找的辅助类,里面封装了一些数据;`SubscriberMethod`订阅方法实体,就是通过注解的方法对应的对象;`Subscription`一个订阅对象。
3. 缓存
4. 线程切换使用方式
5. 反射用法熟悉加强
6. `ThreadLocal`是一个关于创建线程局部变量的类。
    通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。而使用`ThreadLocal`创建的变量只能被当前线程访问,其他线程则无法访问和修改。
7. `CopyOnWriteArrayList`:是一个适合用在读多,写少的并发应用中,它是一个线程安全的集合
8. `ConcurrentHashMap`:是一个应用于高并发的键值对
-------------The End-------------